并行编程和并发
1. 概述
并行编程和并发是现代软件开发中的重要概念,尤其是在处理大规模数据和高性能计算时。并行编程指的是同时执行多个计算任务,而并发则是指多个任务在同一时间段内交替执行。C++ 提供了丰富的工具和库来支持并行编程和并发,使得开发者能够充分利用多核处理器的性能。
2. 理论基础
2.1 并行与并发的区别
- 并行(Parallelism):多个任务在同一时刻同时执行。通常用于多核处理器或多台计算机上。
- 并发(Concurrency):多个任务在同一时间段内交替执行。即使只有一个处理器,也可以通过任务切换实现并发。
2.2 线程与进程
- 进程(Process):操作系统中资源分配的基本单位,每个进程有独立的内存空间。
- 线程(Thread):进程中的执行单元,多个线程共享同一进程的内存空间。
3. C++ 中的并行编程
3.1 std::thread 库
C++11 引入了 std::thread 库,使得线程管理变得更加简单和安全。
3.1.1 创建线程
#include <iostream>
#include <thread>
void hello() {
std::cout << "Hello from thread!" << std::endl;
}
int main() {
std::thread t(hello);
t.join(); // 等待线程完成
std::cout << "Main thread exiting." << std::endl;
return 0;
}
3.1.2 传递参数
#include <iostream>
#include <thread>
void greet(const std::string& name) {
std::cout << "Hello, " << name << "!" << std::endl;
}
int main() {
std::thread t(greet, "Alice");
t.join();
std::cout << "Main thread exiting." << std::endl;
return 0;
}
3.2 线程同步
在多线程编程中,线程同步是确保多个线程正确协作的关键。C++ 提供了多种同步机制,如 std::mutex、std::lock_guard 和 std::condition_variable。
3.2.1 std::mutex
#include <iostream>
#include <thread>
#include <mutex>
std::mutex mtx;
void increment(int& counter) {
for (int i = 0; i < 100000; ++i) {
std::lock_guard<std::mutex> lock(mtx);
++counter;
}
}
int main() {
int counter = 0;
std::thread t1(increment, std::ref(counter));
std::thread t2(increment, std::ref(counter));
t1.join();
t2.join();
std::cout << "Counter: " << counter << std::endl;
return 0;
}
3.2.2 std::condition_variable
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
std::mutex mtx;
std::condition_variable cv;
bool ready = false;
void worker() {
std::unique_lock<std::mutex> lock(mtx);
cv.wait(lock, []{ return ready; });
std::cout << "Worker thread is processing data." << std::endl;
}
void prepare() {
std::this_thread::sleep_for(std::chrono::seconds(1));
std::cout << "Main thread is preparing data." << std::endl;
{
std::lock_guard<std::mutex> lock(mtx);
ready = true;
}
cv.notify_one();
}
int main() {
std::thread t1(worker);
std::thread t2(prepare);
t1.join();
t2.join();
return 0;
}
4. 实践练习
4.1 计算斐波那契数列
编写一个程序,使用多线程计算斐波那契数列的前 N 项。
#include <iostream>
#include <thread>
#include <vector>
void fibonacci(int n, std::vector<int>& result) {
result.resize(n);
result[0] = 0;
if (n > 1) result[1] = 1;
for (int i = 2; i < n; ++i) {
result[i] = result[i-1] + result[i-2];
}
}
int main() {
const int N = 20;
std::vector<int> result;
std::thread t(fibonacci, N, std::ref(result));
t.join();
for (int num : result) {
std::cout << num << " ";
}
std::cout << std::endl;
return 0;
}
4.2 生产者-消费者问题
实现一个简单的生产者-消费者模型,使用 std::mutex 和 std::condition_variable 进行同步。
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <queue>
std::mutex mtx;
std::condition_variable cv;
std::queue<int> buffer;
const int BUFFER_SIZE = 10;
void producer() {
for (int i = 0; i < 20; ++i) {
std::unique_lock<std::mutex> lock(mtx);
cv.wait(lock, []{ return buffer.size() < BUFFER_SIZE; });
buffer.push(i);
std::cout << "Produced: " << i << std::endl;
lock.unlock();
cv.notify_one();
}
}
void consumer() {
for (int i = 0; i < 20; ++i) {
std::unique_lock<std::mutex> lock(mtx);
cv.wait(lock, []{ return !buffer.empty(); });
int value = buffer.front();
buffer.pop();
std::cout << "Consumed: " << value << std::endl;
lock.unlock();
cv.notify_one();
}
}
int main() {
std::thread t1(producer);
std::thread t2(consumer);
t1.join();
t2.join();
return 0;
}
5. 总结
并行编程和并发是现代软件开发中的重要技能。C++ 提供了强大的工具和库来支持这些技术,使得开发者能够编写高效、可靠的多线程程序。通过本教程的学习,你应该能够理解并行编程的基本概念,并能够使用 C++ 编写简单的多线程程序。
6. 进一步学习
- 深入学习 C++ 标准库中的并发工具,如
std::async和std::future。 - 探索更高级的并发模式,如读写锁(
std::shared_mutex)和无锁数据结构。 - 学习如何使用并行算法库(如
std::execution)来优化数据处理任务。
通过不断的实践和学习,你将能够掌握并行编程和并发技术,并在实际项目中应用这些知识。